int AndroidNode::open() {
    chanState = false;
    port = port;
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) { 
        cout <<"ERROR opening socket"<<endl;
        return -1;
    }
    server = gethostbyname(hostname.c_str());
    if (server == NULL) {
        cout <<"ERROR, no such host"<<endl;;
        return -1;
    }
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
    serv_addr.sin_port = htons(port);
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) {
        cout <<"ERROR connecting"<<endl;
        return -1;
    }

    // ---Not sure why adb is not picking messages from HTC on time - 
    unsigned int opt = 4, one = 1;
    setsockopt(sockfd, IPPROTO_TCP,TCP_NODELAY,(void *)&opt, sizeof(opt));
    setsockopt(sockfd, IPPROTO_TCP,SO_KEEPALIVE,(void *)&opt, sizeof(opt));
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof(one));
 
    Message hMsg;
    int ret = recv_msg(&hMsg, 4);
    if((ret == TIMEOUT) || (ret == SOCKET_CLOSED)){
        cout <<" --- No Android Server - exiting....."<<endl;
        return -1;
    }
    cout <<"[ "<<hMsg.str()<<" ] ...."<<endl;
    chanState = true;


    // - start reading thread - 
    //pthread_create(&request_deport_t,NULL,&AndroidNode::_android_read_,(void*)this);
    //pthread_detach(request_deport_t);
    //cout <<"Done Setting up androidMsg Reader ......"<<endl; 

    return 0;
}
    
int AndroidNode::send_msg(Message *hMsg) {
    if((hMsg->message_type() <= 0) || (hMsg->message_type() > ANDROID_USER_LIMIT)) {
        return MALFORMED_MSG;
    } 
    hMsg->add_entry("\n");
    int msg_len = hMsg->android_str().length();
    int n = write(sockfd,hMsg->android_str().c_str(),msg_len);
    if(n <= 0) { 
        chanState = false;
        return SOCKET_CLOSED;
    }
    return SUCCESS;
}
int AndroidNode::recv_msg(Message* hMsg, int timeout) {
    
    int ret;

    fd_set data;
    struct timeval tv;
    tv.tv_sec  = timeout;
    tv.tv_usec = 0;
    FD_ZERO(&data);
    FD_SET(sockfd, &data);
        errno = 0;
    ret = select(FD_SETSIZE, &data,NULL,NULL,&tv);
    if(ret < 0) {
        cout <<"Error:recv_msg("<<errno<<"): select() - Failed"<<endl;
        return SOCKET_CLOSED;
    } else if(ret == 0) {
        return TIMEOUT;
    } else if(FD_ISSET(sockfd,&data)) {
        memset(buffer,0,MAX_MSG_SIZE);
        errno = 0;
        ret = recv(sockfd,buffer,MAX_MSG_SIZE,0);
        if(ret <= 0) {
            cout <<"Error: recv_msg("<<errno<<") - Network partner not available..."<<endl;
            chanState = false;
            return SOCKET_CLOSED;
        }
        buffer[ret-1] = '\0';
        hMsg->read(buffer, true);
        //cout <<"   raw-msg[ "<<buffer<<" ] "<<endl;
        //cout <<"android-msg[ "<<hMsg->str()<<" ] "<<endl;
    }
    return SUCCESS;
}

void AndroidNode::androidBridge(Message& msg, int ttl) {
        
    cout <<"----androidBridge("<<msg.size()<<")------------"<<endl;
    if(msg.message_type() != ANDROID_UNDEFINED) {
        // push user message to android 
        cout <<"Sending MSG[ "<<msg.android_str()<<" ]...."<<endl;
        int ret = send_msg(&msg);
        if(ret != SUCCESS) {
            cout <<"Error: send_msg() : Failed to send message....exiting..."<<endl;
            return;
        }
        // wait for response for all non-broadcast messages - 
        if(msg.message_type() == ANDROID_BROADCAST) {
            sleep(3); 
        } else 
        if(!(msg.message_type() == ANDROID_BROADCAST)) {
            Message msgIn;
            // read response from Android - 
            ret = recv_msg(&msgIn, ttl);
            if(ret == TIMEOUT) { 
                cout <<"info: no messages to read.....sleeping some more- "<<endl;
                return;
            }
            if(ret == SOCKET_CLOSED) {
                cout <<"Error: send_msg() : Failed to send message....exiting..."<<endl;
                chanState = 0;
                exit(0);
            }
            //if(msgIn.message_type() != ANDROID_UNDEFINED) {
            if(msgIn.message_type() == ANDROID_BIOMETRICS) {
                showBiometrics(msgIn);
            } else {
                cout <<"\nVoiceBox:: [ "<<msgIn.str()<<" ]"<<endl;
            }
        }
        msg.reset();
    }
}


void AndroidNode::showBiometrics(Message& msg) {
    int i = 0;
    stringstream strbuf;
    if(msg.size() < 7) {
        cout <<"error: Malformed biometric msg[ "<<msg.str()<<" ] "<<endl;
        return;
    }
    strbuf <<"Facial Biometric Signature:"<<endl;
    strbuf <<"         MsgType[ ANDROID_BIOMETRICS "<<endl;
    strbuf <<"        UserName[ "<<msg.entry(i++)<<endl;
    strbuf <<"           MsgId[ "<<msg.entry(i++)<<endl;
    strbuf <<"Confidence Level[ "<<msg.entry(i++)<<endl;
    strbuf <<"    EyesDistance[ "<<msg.entry(i++)<<endl;
    strbuf <<"    eyesMidPts.x[ "<<msg.entry(i++)<<endl;
    strbuf <<"    eyesMidPts.y[ "<<msg.entry(i++)<<endl;
    strbuf <<"        imageUrl[ "<<msg.entry(i++)<<endl;
    cout <<strbuf.str()<<endl;
}

void AndroidNode::voiceBox() {
    stringstream strbuf;
    string myBuffer;

    while(chanState) {
        Message androidMsg;
        androidMsg.reset();

        cout <<"Enter Activity : \n  --> ";
        memset(buffer,0,MAX_MSG_SIZE);
        if(cin.getline(buffer,MAX_MSG_SIZE).eof() || (strlen(buffer) < 5)) {
            break;
        }   
        myBuffer.assign(buffer);

        if(strncmp(myBuffer.c_str(),"-h",2) == 0) {
            usage();
            continue;
        }

        if(androidMsg.read(myBuffer, false) != 0) {
            cout <<"Error: [ "<<buffer<<" ] AndroidMsg malformed..."<<endl;
            continue;
        }

        if(androidMsg.message_type() == ANDROID_UNDEFINED) {
            cout <<"Undefined messagetype "<<endl;
            continue;
        }
        androidMsg.insert_entry(1,itos(message_counter++));
        androidBridge(androidMsg, 25);
        //sleep(3);
    }
}

void AndroidNode::usage() {
    string usage = "usag()::\n   VoiceClient  -h\n";
    usage += "   VoiceClient <msgType>:<clientid>:<field1>:<field2>...<fieldn>\n";
    usage += "      where msgTye {\n";
    usage += "\t[3] ANDROID_BROADCAST,  // one way voice message - \n";
    usage += "\t[4] ANDROID_QUESTION,   // Question with replay - \n";
    usage += "\t[5] ANDROID_GRID_LOCATION   // Ask humam for a desired map location - \n";
    usage += "\t[6] ANDROID_BIOMETRICS // ask Android to generate facial biometric signature - \n";
    usage += "      }\n\n";
    usage += "      e.g. 3:zeddy:Ask humam for a desired map location\n";
    usage += "      e.g. 4:zeddy:Could you help me please?\n";
    usage += "      e.g. 5:zeddy:Where is west point? Touch it on my touch Tablet.\n";
    usage += "      e.g. 6:zeddy:/sdcard/data/zeddy.png\n";
    usage += "----------------------------------------------------------"; 
    cout <<usage<<endl;
}
string AndroidNode::itos(int i) {
    stringstream ss;
    ss << i;
    return ss.str();
}

int main(int argc, char* argv[]) {
    AndroidNode android("localhost", 7500);
    android.usage();
    if(android.open() != 0) {
        cout <<"Error: Can't connect to the server....exiting..."<<endl<<endl;
        return -1;
    }
    android.voiceBox();
        
    return 0;
}
